package main

import (
	"bufio"
	"bytes"
	"context"
	"dlm/internal/db"
	"dlm/internal/handler"
	"dlm/internal/k8s"
	"dlm/internal/kubeutils"
	"embed"
	"fmt"
	"log"
	"log/slog"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"k8s.io/client-go/kubernetes"
)

var staticFiles embed.FS

func main() {
	initLogger()
	slog.Info("开始初始化数据库客户端...")
	addr, user, password := getDBConfig()
	slog.Info(fmt.Sprintf("数据库配置 地址=%s 用户=%s", addr, user))

	dbClient, err := db.NewClient(addr, user, password)
	if err != nil {
		slog.Error("初始化数据库客户端失败：" + err.Error())
		os.Exit(1)
	}
	db.DB = dbClient
	defer dbClient.Close()
	slog.Info("✅ 数据库客户端初始化完成")

	slog.Info("开始初始化K8s客户端...")
	k8sClient, err := k8s.NewClient()
	if err != nil {
		slog.Error("初始化K8s客户端失败：" + err.Error())
		os.Exit(1)
	}
	slog.Info("✅ k8s客户端初始化完成")

	// 3. 定时采集+清理
	go func() {
		start := time.Now()
		collectAndWriteData(k8sClient, dbClient)
		cleanExpiredData(dbClient)
		slog.Info(fmt.Sprintf("首次数据采集和清理完成，耗时：%s", time.Since(start).Round(time.Millisecond)))

		ticker := time.NewTicker(30 * time.Minute)
		defer ticker.Stop()
		for range ticker.C {
			start := time.Now()
			collectAndWriteData(k8sClient, dbClient)
			cleanExpiredData(dbClient)
			slog.Info(fmt.Sprintf("定时数据采集和清理完成，耗时：%s", time.Since(start).Round(time.Millisecond)))
		}
	}()

	slog.Info("启动Pod清理循环...")
	kubeutils.StartPodCleanupLoop(4 * time.Hour)
	slog.Info("✅ Pod清理循环已在后台启动，每4小时执行一次")

	fileServer := http.FileServer(http.FS(staticFiles))
	http.Handle("/", http.StripPrefix("/", fileServer))

	// 4. 配置HTTP服务
	r := gin.Default()

	// 添加请求日志中间件
	r.Use(func(c *gin.Context) {
		start := time.Now()
		c.Next()
		end := time.Now()

		slog.Info("HTTP请求处理完成",
			"方法", c.Request.Method,
			"路径", c.Request.URL.Path,
			"状态码", c.Writer.Status(),
			"耗时", end.Sub(start),
			"客户端IP", c.ClientIP(),
			// 避免记录Authorization头
		)

		slog.Info("HTTP请求处理完成",
			"方法", c.Request.Method,
			"路径", c.Request.URL.Path,
			"状态码", c.Writer.Status(),
			"耗时", end.Sub(start),
			"客户端IP", c.ClientIP(),
		)
	})

	// 跨域配置
	r.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"http://localhost:8080"},
		AllowMethods:     []string{"GET", "POST", "OPTIONS"},
		AllowHeaders:     []string{"Content-Type", "Authorization"},
		AllowCredentials: true,
		MaxAge:           12 * time.Hour,
	}))

	// 5. 注册接口
	apiGroup := r.Group("/api/storage", JWTAuthMiddleware())
	{
		r.POST("/api/storage/login", handler.Login)

		apiGroup.GET("/trend", handler.GetStorageTrend)
		apiGroup.GET("/namespaces", handler.GetAllNamespaces)
		apiGroup.GET("/data", handler.GetStorageData)

		// 手动采集接口
		apiGroup.POST("/collect", func(c *gin.Context) {
			if err := collectAndWriteData(k8sClient, dbClient); err != nil {
				// 失败时返回统一提示
				c.JSON(http.StatusInternalServerError, gin.H{
					"success": false,
					"message": "采集失败",
				})
			}

			c.JSON(http.StatusOK, gin.H{
				"success": true,
				"message": "手动采集数据成功",
			})
		})
	}

	r.StaticFS("/web", http.Dir("./web/public"))

	r.GET("/", func(c *gin.Context) {
		c.Redirect(http.StatusFound, "/web/login.html")
	})

	slog.Info("HTTP服务启动，端口：8080")
	r.Run(":8080")
}

func JWTAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "未提供Authorization头"})
			c.Abort()
			return
		}

		// 检查Bearer前缀
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization头格式错误"})
			c.Abort()
			return
		}

		// 解析Token
		token, err := jwt.ParseWithClaims(parts[1], &jwt.RegisteredClaims{}, func(token *jwt.Token) (interface{}, error) {
			return []byte("your-secret-key"), nil
		})

		if err != nil || !token.Valid {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的Token"})
			c.Abort()
			return
		}

		c.Next()
	}
}

func getDBConfig() (addr, user, password string) {
	addr = os.Getenv("MYSQL_ADDR")
	user = os.Getenv("MYSQL_USER")
	password = os.Getenv("MYSQL_PASSWORD")
	return
}

func loadNamespaces(path string) ([]string, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var namespaces []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line != "" {
			namespaces = append(namespaces, line)
		}
	}
	return namespaces, scanner.Err()
}

// 采集并写入数据
func collectAndWriteData(k8sClient interface{}, dbClient *db.Client) error {
	slog.Info("开始从K8s采集存储数据...")

	// K8s客户端类型断言
	clientset, ok := k8sClient.(*kubernetes.Clientset)
	if !ok {
		err := fmt.Errorf("k8sClient类型断言失败")
		slog.Error("k8s客户端类型错误", "错误信息", err)
		return err
	}

	namespaces, err := loadNamespaces("configs/namespaces.txt")
	if err != nil {

		slog.Error(fmt.Sprintf("加载命名空间失败：%v", err))
		return fmt.Errorf("加载命名空间失败")
	}

	// 采集K8s数据
	storageDataList, err := k8s.CollectStorageData(clientset, namespaces)
	if err != nil {

		slog.Error(fmt.Sprintf("采集K8s数据失败：%v", err))
		return fmt.Errorf("k8s采集失败")
	}

	// 写入数据库
	if err := db.WriteStorageData(dbClient, storageDataList); err != nil {

		slog.Error(fmt.Sprintf("写入数据库失败：%v", err))
		return fmt.Errorf("数据库写入失败")
	}

	slog.Info(fmt.Sprintf("成功采集并写入 %d 条存储数据", len(storageDataList)))
	return nil
}

// 清理过期数据
func cleanExpiredData(dbClient *db.Client) {
	// 原 log.Println("开始清理过期数据...")
	slog.Info("开始清理过期数据...")

	if err := db.CleanExpiredData(dbClient); err != nil {
		// 原 log.Printf("清理过期数据失败：%v", err)
		slog.Error("清理过期数据失败：" + err.Error())
	} else {
		// 原 log.Println("过期数据清理完成")
		slog.Info("过期数据清理完成")
	}
}

func initLogger() {
	// 完全自定义的日志处理器，不依赖任何默认实现
	h := &customHandler{}
	slog.SetDefault(slog.New(h))

	// 同时处理log包的输出，确保统一格式
	log.SetOutput(&logAdapter{})
	log.SetFlags(0) // 清除默认格式
}

// customHandler 完全自定义slog处理器
type customHandler struct{}

// Enabled 控制日志级别
func (c *customHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return level >= slog.LevelInfo
}

// Handle 核心日志格式化逻辑
func (c *customHandler) Handle(ctx context.Context, r slog.Record) error {
	// 1. 格式化时间
	timeStr := r.Time.Format("2006-01-02 15:04:05")

	// 2. 格式化级别
	levelStr := "[" + r.Level.String() + "]"

	// 3. 处理消息和属性
	var msgBuf bytes.Buffer
	msgBuf.WriteString(r.Message)

	// 处理额外的键值对参数
	r.Attrs(func(a slog.Attr) bool {
		if a.Key != "" {
			msgBuf.WriteString(" " + a.Key + "=" + fmt.Sprint(a.Value.Any()))
		}
		return true
	})

	// 4. 拼接并输出
	fullLine := fmt.Sprintf("%s %s %s\n", timeStr, levelStr, msgBuf.String())
	_, err := os.Stdout.WriteString(fullLine)
	return err
}

// WithAttrs 实现接口（不做额外处理）
func (c *customHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

// WithGroup 实现接口（不做额外处理）
func (c *customHandler) WithGroup(name string) slog.Handler {
	return c
}

// logAdapter 适配log包输出
type logAdapter struct{}

func (l *logAdapter) Write(p []byte) (n int, err error) {
	timeStr := time.Now().Format("2006-01-02 15:04:05")
	msg := strings.TrimSpace(string(p))
	level := "[INFO]"
	if strings.Contains(strings.ToLower(msg), "error") {
		level = "[ERROR]"
	}
	return os.Stdout.WriteString(fmt.Sprintf("%s %s %s\n", timeStr, level, msg))
}

func TimeTrack(start time.Time, operation string) {
	elapsed := time.Since(start)
	slog.Info("操作完成",
		"操作名称", operation,
		"耗时", elapsed.Round(time.Millisecond),
	)
}
